﻿using Aspose.Words;
using Aspose.Words.Tables;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ComTools
{
    public class AsposeWordTools
    {
        private string _docPath;
        private string _docTempPath;

        private bool _isUnion;

        private string _pwd;

        private static Aspose.Words.Document _doc;

       
        public AsposeWordTools(string docPath, string docTempPath)
        {
            
            _docTempPath = docTempPath;
            this._docPath = docPath;
            _doc = new Aspose.Words.Document(_docPath);
           
        }

        public AsposeWordTools(string docPath, string pwd, string docTempPath)
        {
            _pwd = pwd;          
            _docTempPath = docTempPath;
            this._docPath = docPath;
            _doc = new Aspose.Words.Document(_docPath, new Aspose.Words.LoadOptions() { Password = pwd });
        }
     
        /// <summary>
        /// 取得当前文档页数
        /// </summary>
        /// <returns></returns>
        public int getPageCount()
        {
            return _doc.PageCount;
        }

        /// <summary>
        /// 保存为图片
        /// </summary>
        /// <param name="savePath">图片保存路径</param>
        /// <param name="pageIndex">保存的页码</param>
        /// <returns></returns>
        public string saveToImg(string savePath, int pageNum = 1, Aspose.Words.SaveFormat sf = Aspose.Words.SaveFormat.Jpeg)
        {
            if (_isUnion)
            {
                _doc.Save(_docTempPath, Aspose.Words.SaveFormat.Docx);
                if (string.IsNullOrEmpty(_pwd))
                    _doc = new Aspose.Words.Document(_docTempPath);
                else
                    _doc = new Aspose.Words.Document(_docTempPath, new Aspose.Words.LoadOptions() { Password = _pwd });
                _isUnion = false;
            }

            Aspose.Words.Saving.ImageSaveOptions options = new Aspose.Words.Saving.ImageSaveOptions(sf);
            options.Resolution = 120;
            options.PrettyFormat = true;
            options.UseAntiAliasing = true;
            if (pageNum > 0)
            {
                if (pageNum > _doc.PageCount)
                    return "ERR:超出页码数";
                options.PageIndex = pageNum - 1;
            }

            _doc.Save(savePath, options);
            return "OK:";
        }

        /// <summary>
        /// 保存文档
        /// </summary>
        /// <param name="savePath"></param>
        /// <returns></returns>
        public string save(string savePath, Aspose.Words.SaveFormat sf = Aspose.Words.SaveFormat.Docx)
        {
            if (_isUnion && sf != Aspose.Words.SaveFormat.Docx)
            {
                _doc.Save(_docTempPath, Aspose.Words.SaveFormat.Docx);
                if (string.IsNullOrEmpty(_pwd))
                    _doc = new Aspose.Words.Document(_docTempPath);
                else
                    _doc = new Aspose.Words.Document(_docTempPath, new Aspose.Words.LoadOptions() { Password = _pwd });
                _isUnion = false;
            }
            _doc.Save(savePath, sf);

            return "OK:";
        }

        public string save()
        {
            _doc.Save(_docTempPath, Aspose.Words.SaveFormat.Docx);
            return "OK:";
        }

        public string getLoadUrl()
        {
            _doc.Save(_docTempPath, Aspose.Words.SaveFormat.Docx);
            string reUrl = _docTempPath;
            reUrl = reUrl.Replace(System.Web.HttpContext.Current.Server.MapPath("/"), "/");
            return "OK:" + reUrl;
        }

        /// <summary>
        /// 拼接文档
        /// </summary>
        /// <param name="unionDocPath">需拼接的文档</param>
        /// <returns></returns>
        public string unionDoc(string unionDocPath, bool isAddByNewPage = true)
        {
            Aspose.Words.Document UnionDoc = new Aspose.Words.Document(unionDocPath);

            if (isAddByNewPage)
                UnionDoc.FirstSection.PageSetup.SectionStart = Aspose.Words.SectionStart.NewPage;
            else
                UnionDoc.FirstSection.PageSetup.SectionStart = Aspose.Words.SectionStart.Continuous;
            _doc.AppendDocument(UnionDoc, Aspose.Words.ImportFormatMode.KeepSourceFormatting);
            //_doc.AppendDocument(UnionDoc, Aspose.Words.ImportFormatMode.KeepDifferentStyles);
            _isUnion = true;
            return "OK:";
        }

        /// <summary>
        /// 书签写入文字
        /// </summary>
        /// <param name="markName"></param>
        /// <param name="txt"></param>
        /// <param name="isMarkDelete">是否删除书签</param>
        /// <returns></returns>
        public string markToTxt(string markName, string txt, bool isMarkDelete = true)
        {
            foreach (Aspose.Words.Bookmark mark in _doc.Range.Bookmarks)
            {
                if (mark == null) continue;
                if (mark.Name != markName) continue;
                mark.Text = txt;
                if (isMarkDelete) mark.Remove();
                break;
            }
            return "OK:";
        }

        public static string markToTxt(string markName, string txt, fontStyle style, bool isMarkDelete = true)
        {
            foreach (Aspose.Words.Bookmark mark in _doc.Range.Bookmarks)
            {
                if (mark == null) continue;
                if (mark.Name != markName) continue;

                Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(_doc);
                builder.MoveToBookmark(mark.Name);

                if (style.color != null) builder.Font.Color = style.color;
                if (!string.IsNullOrEmpty(style.fontName)) builder.Font.Name = style.fontName;
                builder.Font.Bold = style.isBold;
                builder.Font.Italic = style.isItalic;
                if (style.size > 0) builder.Font.Size = style.size;

                mark.Text = "";
                builder.Write(txt);

                if (isMarkDelete) mark.Remove();
                break;
            }
            return "OK:";
        }

        /// <summary>
        /// 书签插入图片
        /// </summary>
        /// <param name="markName">书签名</param>
        /// <param name="imgPath">图片路径</param>
        /// <param name="width">图片长</param>
        /// <param name="height">图片宽</param>
        /// <param name="top">水平离距</param>
        /// <param name="left">直离距</param>
        /// <param name="rhp">水平对齐方式</param>
        /// <param name="rvp">直对齐方式</param>
        /// <param name="wt">图片显示方式</param>
        /// <param name="isBehindText">是否在文字下方（悬浮时）</param>
        /// <param name="isMarkDelete">是否删除书签</param>
        /// <returns></returns>
        public string markToImg(string markName, string imgPath, int width = 150, int height = 150, int top = 0, int left = 0, Aspose.Words.Drawing.RelativeHorizontalPosition rhp = Aspose.Words.Drawing.RelativeHorizontalPosition.Character,
           Aspose.Words.Drawing.RelativeVerticalPosition rvp = Aspose.Words.Drawing.RelativeVerticalPosition.Paragraph,
           Aspose.Words.Drawing.WrapType wt = Aspose.Words.Drawing.WrapType.None, bool isBehindText = true, bool isMarkDelete = true)
        {
            foreach (Aspose.Words.Bookmark mark in _doc.Range.Bookmarks)
            {
                if (mark == null) continue;
                if (mark.Name != markName) continue;
                mark.Text = "";
                Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(_doc);
                if (System.IO.File.Exists(imgPath))
                {
                    builder.MoveToBookmark("PHOTO");
                    Aspose.Words.Drawing.Shape imgShape = builder.InsertImage(imgPath, rhp, left, rvp, top, width, height, wt);
                    imgShape.BehindText = isBehindText;
                    if (isMarkDelete) mark.Remove();
                    //Aspose.Words.Drawing.WrapType.Through  穿越型
                    //Aspose.Words.Drawing.WrapType.None 于文字上方
                    //Aspose.Words.Drawing.WrapType.TopBottom 上下型
                    //Aspose.Words.Drawing.WrapType.Tight 紧密型
                    //Aspose.Words.Drawing.WrapType.Inline 钳入型
                    //Aspose.Words.Drawing.WrapType.Square 四周型
                }

                break;
            }
            return "OK:";
        }


        /// <summary>
        /// 表格新增行
        /// </summary>
        /// <param name="tableIndex">操作第几个表格0起</param>
        /// <param name="copyRowIndex">复制第几行格式0起，小于0时默认最后一行</param>
        /// <param name="dv">值列表</param>
        /// <returns></returns>
        public string tableAddRow(int tableIndex, int copyRowIndex, System.Collections.Generic.Dictionary<string, string> dv)
        {
            Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(_doc);

            Aspose.Words.NodeCollection allTables = _doc.GetChildNodes(Aspose.Words.NodeType.Table, true); //拿到所有表格
            Aspose.Words.Tables.Table table = allTables[tableIndex] as Aspose.Words.Tables.Table; //拿到第tableIndex个表格

            Aspose.Words.Node row = copyRowIndex < 0 ? table.LastRow.Clone(true) : table.Rows[copyRowIndex].Clone(true);
            Aspose.Words.Range range = table.LastRow.Range;
            foreach (string key in dv.Keys)
                range.Replace(new System.Text.RegularExpressions.Regex(key), dv[key]);
            table.Rows.Add(row); //添加一行

            return "OK:";
        }


        /// <summary>
        /// 删除表格行
        /// </summary>
        /// <param name="tableIndex">操作第几个表格0起</param>
        /// <param name="copyRowIndex">第几行格式0起，小于0时默认最后一行</param>
        /// <returns></returns>
        public string tableDelRow(int tableIndex, int copyRowIndex = -1)
        {
            Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(_doc);

            Aspose.Words.NodeCollection allTables = _doc.GetChildNodes(Aspose.Words.NodeType.Table, true); //拿到所有表格
            Aspose.Words.Tables.Table table = allTables[tableIndex] as Aspose.Words.Tables.Table; //拿到第tableIndex个表格

            if (copyRowIndex < 0)
                table.LastRow.Remove();
            else
                table.Rows[copyRowIndex].Remove();
            return "OK:";
        }

        /// <summary>
        /// 单元格插入图片
        /// </summary>
        /// <param name="tableIndex"></param>
        /// <param name="rowIndex"></param>
        /// <param name="cellIndex"></param>
        /// <param name="imgPath"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public string cellToImg(int tableIndex, int rowIndex, int cellIndex, string imgPath, int width = 150, int height = 150)
        {
            Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(_doc);

            builder.MoveToCell(tableIndex, rowIndex, cellIndex, 0);

            Aspose.Words.Drawing.Shape imgShape = builder.InsertImage(imgPath, Aspose.Words.Drawing.RelativeHorizontalPosition.Column, 0, Aspose.Words.Drawing.RelativeVerticalPosition.Line, 0, width, height, Aspose.Words.Drawing.WrapType.Inline);

            return "OK:";
        }

        public string toProtect(string pwd = "")
        {
            _pwd = pwd;
            if (!string.IsNullOrEmpty(pwd))
                _doc.Protect(Aspose.Words.ProtectionType.AllowOnlyFormFields, pwd);
            else
                _doc.Unprotect();
            return "OK:";
        }

        /// <summary>
        /// 导出word文档里指定的表数据
        /// </summary>
        /// <param name="tableIndex"></param>
        /// <param name="isTitleActive"></param>
        /// <param name="colIndexList"></param>
        /// <returns></returns>
        public System.Data.DataTable getTableData(int tableIndex, bool isTitleActive = true, List<int> colIndexList = null)
        {
            System.Data.DataTable dt = new System.Data.DataTable();

            Aspose.Words.NodeCollection allTables = _doc.GetChildNodes(Aspose.Words.NodeType.Table, true); //拿到所有表格
            Aspose.Words.Tables.Table table = allTables[tableIndex] as Aspose.Words.Tables.Table; //拿到第tableIndex个表格

            int rowIndex = 0;
            int tableColNum = table.Rows[0].Cells.Count;
            if (isTitleActive)
            {
                for (int i = 0, j = tableColNum; i < j; i++)
                {
                    if (colIndexList == null || colIndexList.Contains(i))
                        dt.Columns.Add(table.Rows[0].Cells[i].GetText());
                }
                rowIndex++;
            }
            else
            {
                for (int i = 0, j = tableColNum; i < j; i++)
                {
                    if (colIndexList == null || colIndexList.Contains(i))
                        dt.Columns.Add(i.ToString());
                }
            }

            for (int iR = rowIndex, jR = table.Rows.Count; iR < jR; iR++)
            {
                System.Data.DataRow dr = dt.NewRow();
                for (int i = 0, j = tableColNum; i < j; i++)
                {
                    if (colIndexList == null || colIndexList.Contains(i))
                    {
                        if (isTitleActive)
                            dr[table.Rows[0].Cells[i].GetText()] = table.Rows[iR].Cells[i].GetText();
                        else
                            dr[i.ToString()] = table.Rows[iR].Cells[i].GetText();
                    }
                }
                dt.Rows.Add(dr);
            }

            return dt;
        }

        public List<Aspose.Words.PageSetup> getSectionPageSetups()
        {
            if (_isUnion)
            {
                _doc.Save(_docTempPath, Aspose.Words.SaveFormat.Docx);
                if (string.IsNullOrEmpty(_pwd))
                    _doc = new Aspose.Words.Document(_docTempPath);
                else
                    _doc = new Aspose.Words.Document(_docTempPath, new Aspose.Words.LoadOptions() { Password = _pwd });
                _isUnion = false;
            }

            List<Aspose.Words.PageSetup> xList = new List<Aspose.Words.PageSetup>();

            foreach (Aspose.Words.Section sec in _doc)
            {
                xList.Add(sec.PageSetup);
            }

            //xList.ForEach(p => p.PaperSize = Aspose.Words.PaperSize.A4);//全部设置
            //xList[3].PaperSize = Aspose.Words.PaperSize.A4;//单项设置
            return xList;
        }

        public Aspose.Words.PageSetup getPageSetup()
        {
            if (_isUnion)
            {
                _doc.Save(_docTempPath, Aspose.Words.SaveFormat.Docx);
                if (string.IsNullOrEmpty(_pwd))
                    _doc = new Aspose.Words.Document(_docTempPath);
                else
                    _doc = new Aspose.Words.Document(_docTempPath, new Aspose.Words.LoadOptions() { Password = _pwd });
                _isUnion = false;
            }

            Aspose.Words.DocumentBuilder builder = new Aspose.Words.DocumentBuilder(_doc);
            Aspose.Words.PageSetup pageSet = builder.PageSetup;

            //pageSet.PaperSize = Aspose.Words.PaperSize.A4;//设置纸张
            //pageSet.Orientation = Aspose.Words.Orientation.Portrait;//纵向打印模式
            //pageSet.VerticalAlignment = Aspose.Words.PageVerticalAlignment.Top;//顶部靠齐
            //pageSet.TopMargin = 28.35;//以磅为单位返回或设置上边距的大小。Double类型，可读写。此属性与“上”选项对应。
            //pageSet.BottomMargin = 28.35;//以磅为单位返回或设置底端边距的大小。Double类型，可读写。此属性与“下”选项对应。
            //pageSet.RightMargin = 28.35;//以磅为单位返回或设置右边距的大小。Double类型，可读写。此属性与“右”选项对应。
            //pageSet.LeftMargin = 28.35;//以磅为单位返回或设置左边距的大小。Double类型，可读写。此属性与“左”选项对应。
            //pageSet.FooterDistance = 28.35;//以磅为单位返回或设置页脚到页面底端的距离。Double类型，可读写。此属性与“页脚”选项对应。
            //pageSet.HeaderDistance = 28.35;//以磅为单位返回或设置页面顶端到页眉的距离。Double类型，可读写。此属性与“页眉”选项对应。
            //1磅约等于0.03527厘米 所以这里可以这样表示 2CM = 2 / 0.03527
    
        return pageSet;

        }


        public static void FillContentByTable(string templatePath, string targetPath,int count,int columnCount,int stRowindex, List<string[]> values)
        {
            try
            {
                Document doc = new Document(templatePath);
                DocumentBuilder builder = new DocumentBuilder(doc);
                //获取表格节点集合
                NodeCollection tables = doc.GetChildNodes(NodeType.Table, true);
                #region 动态添加表格中的数据
                //拿到word文档中的表格：根据word文档中表格索引定位表格
                Table table = tables[0] as Table;
                var roww = table.Rows[stRowindex];
                for (int i = 0; i < count; i++)
                {
                    var row = CreateRow(columnCount, values[i], doc);
                    table.Rows.Insert(stRowindex+i, row); //将此行插入第一行的上方 
                }
                #endregion
                doc.Save(targetPath, SaveFormat.Docx);
            }
            catch(Exception ex)
            {

            }
        }

        public static void FillContentByTemplateTable(string templatePath, string targetPath, int count, int columnCount, int stRowindex, List<string[]> values,Dictionary<string, string> dic)
        {
            try
            {
                Document doc = new Document(templatePath);
                DocumentBuilder builder = new DocumentBuilder(doc);
                //获取表格节点集合
                NodeCollection tables = doc.GetChildNodes(NodeType.Table, true);
                #region 动态添加表格中的数据
                //拿到word文档中的表格：根据word文档中表格索引定位表格
                Table table = tables[0] as Table;
                var roww = table.Rows[stRowindex];
                foreach (var key in dic.Keys)   //循环键值对
                {
                    foreach (Aspose.Words.Bookmark mark in doc.Range.Bookmarks)
                    {
                        if (mark == null) continue;
                        if (mark.Name != key) continue;
                        mark.Text = dic[key];                      
                        break;
                    }
                }
                int tableIndex = 0;
                //定位到表格
                builder.MoveToBookmark("table");

                for (int i = 0; i < count; i++)
                {
                    //var row = CreateRow(columnCount, values[i], doc);
                    var row = roww.Clone(true);
                    table.Rows.RemoveAt(stRowindex + i); //移除多余的空行
                    //将复制的行插入当前行的上方
                    table.Rows.Insert(stRowindex + i, row);
                    for (int m = 0; m < columnCount; m++)
                    {
                        builder.MoveToCell(tableIndex, stRowindex + i, m, 0);
                        builder.Write(values[i][m]);
                    }
                   
                }
              

                doc.Save(targetPath);
                #endregion
                //doc.Save(targetPath, SaveFormat.Docx);
            }
            catch (Exception ex)
            {

            }
        }

        public static Row CreateRow(int columnCount, string[] columnValues, Document doc)
        {
            Row r = new Row(doc);
            for (int i = 0; i < columnCount; i++)
            {
                if (columnValues.Length > i)
                {
                    var cell = CreateCell(columnValues[i], doc);
                    r.Cells.Add(cell);
                }
                else
                {
                    var cell = CreateCell("", doc);
                    r.Cells.Add(cell);
                }

            }
            return r;
        }
        public static Cell CreateCell(string value, Document doc)
        {

            Cell c = new Cell(doc);
            Paragraph p = new Paragraph(doc);
            p.AppendChild(new Run(doc, value));
            c.AppendChild(p);
            return c;
        }
    }

    public class fontStyle
    {
        /// <summary>
        /// 字体
        /// </summary>
        public string fontName { get; set; }
        /// <summary>
        /// 字体大小
        /// </summary>
        public double size { get; set; }
        //是否加粗
        public bool isBold { get; set; }
        //是否斜体
        public bool isItalic { get; set; }
        /// <summary>
        /// 颜色
        /// </summary>
        public System.Drawing.Color color { get; set; }

    }


    public class File2DicOper
    {
        /// <summary>
        /// 大文件多次复制文件  true：复制成功   false：复制失败
        /// </summary>
        /// <param name="soucrePath">原始文件路径包含文件名</param>
        /// <param name="targetPath">复制目标文件路径，包含文件名</param>
        /// <returns></returns>
        public bool CopyFile(string soucrePath, string targetPath)
        {
            try
            {
                //读取复制文件流
                using (FileStream fsRead = new FileStream(soucrePath, FileMode.Open, FileAccess.Read))
                {
                    //写入文件复制流
                    using (FileStream fsWrite = new FileStream(targetPath, FileMode.OpenOrCreate, FileAccess.Write))
                    {
                        byte[] buffer = new byte[1024 * 1024 * 2]; //每次读取2M
                        //可能文件比较大，要循环读取，每次读取2M
                        while (true)
                        {
                            //每次读取的数据    n：是每次读取到的实际数据大小
                            int n = fsRead.Read(buffer, 0, buffer.Count());
                            //如果n=0说明读取的数据为空，已经读取到最后了，跳出循环
                            if (n == 0)
                            {
                                break;
                            }
                            //写入每次读取的实际数据大小
                            fsWrite.Write(buffer, 0, n);
                        }
                    }
                }
                return true;
            }
            catch (System.Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// Copy文件夹至
        /// </summary>
        /// <param name="sourceDir">原路径</param>
        /// <param name="toDir">目标路径</param>
        public static void CopyDirectInfo(string sourceDir, string toDir)
        {
            if (!Directory.Exists(sourceDir))
            {
                throw new ApplicationException("Source directory does not exist");
            }
            if (!Directory.Exists(toDir))
            {
                Directory.CreateDirectory(toDir);
            }
            DirectoryInfo directInfo = new DirectoryInfo(sourceDir);
            //copy files
            FileInfo[] filesInfos = directInfo.GetFiles();
            foreach (FileInfo fileinfo in filesInfos)
            {
                string fileName = fileinfo.Name;
                File.Copy(fileinfo.FullName, toDir + @"/" + fileName, true);
            }
            //copy directory
            foreach (DirectoryInfo directoryPath in directInfo.GetDirectories())
            {
                string toDirPath = toDir + @"/" + directoryPath.Name;
                CopyDirectInfo(directoryPath.FullName, toDirPath);
            }
        }

    }
}

